﻿using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using X.Infrastructure.WPF.Extends;

namespace X.WPF.Controls.Helpers
{
    /// <summary>
    /// 密码框帮助类
    /// </summary>
    public class PasswordBoxHelper
    {

        #region # 字段及构造器

        /// <summary>
        /// 静态构造器
        /// </summary>
        static PasswordBoxHelper()
        {
            //注册附加属性
            PasswordBoxHelper.IsMonitoringProperty = DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, PasswordBoxHelper.IsMonitoringChangedCallback));
            PasswordBoxHelper.PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordBoxHelper), new PropertyMetadata("", PasswordBoxHelper.PasswordChangedCallback));
            PasswordBoxHelper.ShowRevealedButtonProperty = DependencyProperty.RegisterAttached("ShowRevealedButton", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(true));
            PasswordBoxHelper.IsRevealedButtonBehaviorEnableProperty = DependencyProperty.RegisterAttached("IsRevealedButtonBehaviorEnable", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, PasswordBoxHelper.IsRevealedButtonBehaviorEnableChangedCallback));
            PasswordBoxHelper.ShowRevealedProperty = DependencyProperty.RegisterAttached("ShowRevealed", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false));

        }


        /// <summary>
        /// 默认构造器
        /// </summary>
        public PasswordBoxHelper()
        {
        }

        #endregion

        #region # 附加属性 

        #region 是否监控 —— string IsMonitoring
        /// <summary>
        /// 是否监控附加属性
        /// </summary>
        public static DependencyProperty IsMonitoringProperty;

        /// <summary>
        /// 获取是否监控
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static string GetIsMonitoring(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(PasswordBoxHelper.IsMonitoringProperty);
        }

        /// <summary>
        /// 设置是否监控
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetIsMonitoring(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(PasswordBoxHelper.IsMonitoringProperty, value);
        }
        #endregion

        #region 密码 —— string Password
        /// <summary>
        /// 密码附加属性
        /// </summary>
        public static DependencyProperty PasswordProperty;

        /// <summary>
        /// 获取密码
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static string GetPassword(DependencyObject dependencyObject)
        {
            return (string)dependencyObject.GetValue(PasswordBoxHelper.PasswordProperty);
        }

        /// <summary>
        /// 设置密码
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetPassword(DependencyObject dependencyObject, string value)
        {
            dependencyObject.SetValue(PasswordBoxHelper.PasswordProperty, value);
        }
        #endregion

        #region 显示密码按钮是否显示 —— bool ShowRevealedButton
        /// <summary>
        /// 显示密码按钮是否显示附加属性
        /// </summary>
        public static DependencyProperty ShowRevealedButtonProperty;

        /// <summary>
        /// 获取显示密码按钮是否显示
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetShowRevealedButton(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(PasswordBoxHelper.ShowRevealedButtonProperty);
        }

        /// <summary>
        /// 设置显示密码按钮是否显示
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetShowRevealedButton(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(PasswordBoxHelper.ShowRevealedButtonProperty, value);
        }

        #endregion

        #region 显示密码按钮行为是否启用 —— bool IsRevealedButtonBehaviorEnable
        /// <summary>
        /// 显示密码按钮行为是否启用附加属性
        /// </summary>
        public static DependencyProperty IsRevealedButtonBehaviorEnableProperty;

        /// <summary>
        /// 获取显示密码按钮行为是否启用
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetIsRevealedButtonBehaviorEnable(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(PasswordBoxHelper.IsRevealedButtonBehaviorEnableProperty);
        }

        /// <summary>
        /// 设置显示密码按钮行为是否启用
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetIsRevealedButtonBehaviorEnable(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(PasswordBoxHelper.IsRevealedButtonBehaviorEnableProperty, value);
        }
        #endregion

        #region 是否显示密码 —— bool ShowRevealed
        /// <summary>
        /// 是否显示密码附加属性
        /// </summary>
        public static DependencyProperty ShowRevealedProperty;

        /// <summary>
        /// 获取是否显示密码
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetShowRevealed(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(PasswordBoxHelper.ShowRevealedProperty);
        }

        /// <summary>
        /// 设置是否显示密码
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="value"></param>
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static void SetShowRevealed(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(PasswordBoxHelper.ShowRevealedProperty, value);
        }
        #endregion

        #endregion

        #region # 路由事件

        #endregion

        #region # 事件处理程序

        #region 显示密码按钮点击事件 —— void RevealedButtonClick(object sender, RoutedEventArgs e)
        /// <summary>
        /// 显示密码按钮点击事件
        /// </summary> 
        private static void RevealedButtonClick(object sender, RoutedEventArgs e)
        {
            Button button = (Button)sender;

            DependencyObject parent = button.GetAncestors().FirstOrDefault(a => a is PasswordBox);

            bool showRevealed = PasswordBoxHelper.GetShowRevealed(parent);

            PasswordBoxHelper.SetShowRevealed(parent, !showRevealed);

            if (showRevealed)
            {
                PasswordBox passwordBox = (PasswordBox)parent;
                passwordBox?.Focus();
                passwordBox?.GetType().GetMethod("Select", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(passwordBox, new object[] { passwordBox.Password.Length, 0 });
            }
            else
            {
            }
        }
        #endregion

        #region 密码改变事件 —— void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
        /// <summary>
        /// 密码改变事件
        /// </summary> 
        private static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox passwordBox = (PasswordBox)sender;
            e.Handled = true;

            PasswordBoxHelper.SetPassword(passwordBox, passwordBox.Password);
        }
        #endregion

        #endregion

        #region # 回调方法

        #region 是否监控改变回调方法 —— static void IsMonitoringChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 是否监控改变回调方法
        /// </summary>
        protected static void IsMonitoringChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            bool newValue = (bool)eventArgs.NewValue;

            switch (dependencyObject)
            {
                case PasswordBox passwordBox:
                    if (newValue)
                    {
                        passwordBox.BeginInvoke(() => PasswordBoxHelper.PasswordBoxPasswordChanged(passwordBox, new RoutedEventArgs(PasswordBox.PasswordChangedEvent, passwordBox)));

                        passwordBox.PasswordChanged += PasswordBoxHelper.PasswordBoxPasswordChanged;
                    }
                    else
                    {
                        passwordBox.PasswordChanged -= PasswordBoxHelper.PasswordBoxPasswordChanged;
                    }
                    break;
            }
        }

        #endregion

        #region 密码改变事件回调方法 —— void PasswordChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        /// <summary>
        /// 密码改变事件回调方法
        /// </summary>
        private static void PasswordChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            PasswordBox passwordBox = (PasswordBox)dependencyObject;

            bool showRevealed = PasswordBoxHelper.GetShowRevealed(passwordBox);
            if (!showRevealed)
                return;

            passwordBox.Password = (string)eventArgs.NewValue;
        }
        #endregion

        #region 显示密码按钮行为可用状态改变回调方法 —— static void IsRevealedButtonBehaviorEnableChangedCallback(DependencyObject dependencyObject...
        /// <summary>
        /// 清空按钮行为可用状态改变回调方法
        /// </summary>
        private static void IsRevealedButtonBehaviorEnableChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
        {
            Button button = (Button)dependencyObject;

            if (eventArgs.OldValue == eventArgs.NewValue || button == null)
                return;

            button.Click += PasswordBoxHelper.RevealedButtonClick;
        }
        #endregion

        #endregion

        #region # 方法

        #endregion

    }
}